package com.hyou.starter.autoconfigure.mybatis;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.CollectionUtils;

public class MybatisUtil {
    
    private static final Logger log = LoggerFactory.getLogger(MybatisUtil.class);
    
    private static final String DFT_MYBATIS_CONFIG = "classpath:mybatis-config.xml";
    
    private static final String DFT_RESOURCE_PATTERN = "classpath*:mappers/**/*Mapper.xml";
    
    private MybatisUtil() {
        
    }
    
    /**
     * <pre>
     * 构建SqlSessionFactory
     * 
     * 版本修改历史记录：
     * 1) 1.0.0 2018-09-30 10:00:35 Hyou 修改
     * </pre>
     * 
     * @param dsKey 数据源Key
     * @param dataSource 数据源对象
     * @param mybatisResourceProp MyBatis配置参数对象
     * @return SqlSessionFactory
     * @throws Exception PathMatchingResourcePatternResolver#getResources()
     */
    public static SqlSessionFactory sqlSessionFactory(String dsKey, DataSource dataSource,
            MybatisResourceProp mybatisResourceProp)
            throws Exception {
        
        String rootMybatisConfig = mybatisResourceProp.getMybatisConfig();
        if (StringUtils.isBlank(rootMybatisConfig)) {
            rootMybatisConfig = DFT_MYBATIS_CONFIG;
        }
        
        List<String> rootResourcePatterns = mybatisResourceProp.getResourcePatterns();
        if (CollectionUtils.isEmpty(rootResourcePatterns)) {
            rootResourcePatterns = new ArrayList<>();
            rootResourcePatterns.add(DFT_RESOURCE_PATTERN);
        }
        
        String finalMybatisConfig;
        List<String> finalResourcePatterns;
        
        Map<String, MybatisResourceProp> mybatisMap = mybatisResourceProp.getMybatisMap();
        MybatisResourceProp subProp = mybatisMap.get(dsKey);
        
        if (subProp != null) {
            String subMybatisConfig = subProp.getMybatisConfig();
            if (StringUtils.isNotBlank(subMybatisConfig)) {
                finalMybatisConfig = subMybatisConfig;
            } else {
                finalMybatisConfig = rootMybatisConfig;
            }
            
            List<String> subResourcePatterns = subProp.getResourcePatterns();
            if (CollectionUtils.isEmpty(subResourcePatterns)) {
                finalResourcePatterns = rootResourcePatterns;
            } else {
                finalResourcePatterns = subResourcePatterns;
            }
        } else {
            finalMybatisConfig = rootMybatisConfig;
            finalResourcePatterns = rootResourcePatterns;
        }
        
        log.info("final mybatis config : {}", finalMybatisConfig);
        log.info("final resource pattern : {}", finalResourcePatterns);
        
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(dataSource);
        
        PathMatchingResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
        sqlSessionFactory.setConfigLocation(resourceLoader.getResource(finalMybatisConfig));
        
        List<org.springframework.core.io.Resource> allResources = new ArrayList<>();
        for (String resourcePattern : finalResourcePatterns) {
            org.springframework.core.io.Resource[] mapperLocations = resourceLoader.getResources(resourcePattern);
            allResources.addAll(Arrays.asList(mapperLocations));
        }
        
        int rsSize = allResources.size();
        org.springframework.core.io.Resource[] allMapperLocations = new org.springframework.core.io.Resource[rsSize];
        sqlSessionFactory.setMapperLocations(allResources.toArray(allMapperLocations));
        
        return sqlSessionFactory.getObject();
    }
    
}
